Spring的web MVC框架和其他web MVC框架一样,由注解驱动,围绕着一个核心的用来分发请求到控制器的Servlet设计,并提供了其他的功能来简便web应用程序开发。但是,DispathcerServlet做的远不止这些。它完全集成了Spring IoC容器,让你允许使用其他Spring的功能。
Spring Web MVC的DispatcherServlet工作流程如下图所示。了解设计模式的读者会意识到DispatcherServletFront Controller设置模式的一种(这种模式被Spring Web MVC和其他领先的web框架所共享)。
Figure 22.1. The request processing workflow in Spring Web MVC(high level)
image
DispatcherServlet实际上就是一个Servlet(继承了HttpServlet),因此可以被声明在你的web应用中。你需要通过URL mapping映射到你希望DispatcherServlet处理的请求。下面是一个Servlet 3.0+的环境中标准的Java EE Servlet配置:

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {
        ServletRegistration.Dynamic registration = container.addServlet("example", new DispatcherServlet());
        registration.setLoadOnStartup(1);
        registration.addMapping("/example/*");
    }
}

上面这个例子中,任何以/example开头的请求会被叫做exampleDispathcerServlet处理。
WebApplicationInitializer是Spring MVC提供的接口,让你基于代码的配置可以被检测并自动应用到任何Servlet 3容器中。这个接口抽象的实现是AbstractAnnotationConfigDispathcerServletInitializer,它使注册DispathcerServlet更容易,只要简单的指定它的servlet映射和配置类列表——也建议你用这种方式类设置你的Spring MVC应用。查看Code-based Servlet container initializaiont了解更多信息。
DispathcerServlet是一个Servlet(继承自HttpServlet),因此可以在你的web application的web.xml中声明。你需要在相同的web.xml中用URL mapping指定你希望DispathcerServlet处理的请求。它是一个标准的Java EE Servlet配置;下面的例子展示了如何声明和映射DispatcherServlet
下面的web.xml和上面的基于代码的配置是相同的:

<web-app>
    <servlet>
        <servlet-name>example</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>example</servlet-name>
        <url-pattern>/example/*</url-pattern>
    </servlet-mapping>

</web-app>

Spring中ApplicationContext实例可以被设置范围,具体见7.15节,"Additional capabilities of the ApplicationContext"。在Web MVC框架中,每个DispatcherServlet有它自己的WebApplicationContext,每个WebApplicationContext继承了定义在根WebApplicationContext。根WebApplicationContext应该包含所有需要被其他context或是Servlet实例共享的bean结构。这些继承来的bean可以在servlet-特指的范围下被覆盖,并且你可以为servlet实例定义bean的新的特定的范围。
Figure 22.2. Typical context hierarchy in Spring Web MVC
image
DispatcherServlet初始化之后,Spring MVC会在你web应用的WEB-INF下查找一个叫[servlet-name]-servlet.xml的文件,并创建定义在这个文件中的bean,覆盖全局范围下的相同名字的bean定义。
考虑(在web.xml中)有下面DispatcherServlet Servlet配置:

<web-app>
    <servlet>
        <servlet-name>golfing</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>golfing</servlet-name>
        <url-pattern>/golfing/*</url-pattern>
    </servlet-mapping>
</web-app>

在你的应用中需要一个叫做/WEB-INF/golfing-servlet.xml的文件;这个文件将包含你所有的特定于Spring Web MVC的组件(beans)。你可以通过Servlet初始化的参数来改变这个配置文件的实际位置(详见下面)。
当然在只有一个DispatcherServlet的环境下,只有根上下文也是可以的。
image
可以通过像下面这个,设置空的contextConfigLocation作为servlet初始化参数来实现:

<web-app>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/root-context.xml</param-value>
    </context-param>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

WebApplicationContext拓展了ApplicationContext,增加了web应用必要的一些功能。和普通ApplicationContext不同,它可以解析主题(见22.9节,"Using themes"),并且它(通过连接到ServletContext)知道和哪个Servlet关联。WebApplicationServletContext绑定,在你需要访问WebApplicationContext时,通过RequestContextUtis的静态方法可以查找到WebApplication
我们也可以用基于Java的方式实现上面的配置:

public class GolfingWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        // GolfingAppConfig defines beans that would be in root-context.xml
        return new Class[] { GolfingAppConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        // GolfingWebConfig defines beans that would be in golfing-servlet.xml
        return new Class[] { GolfingWebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/golfing/*" };
    }
}

22.2.1 Specail Bean Types In the WebApplicationContext

Spring DispatcherServlet用特殊的bean来处理请求和渲染合适的视图。这些bean是Spring MVC的一部分。你可以选择WebApplicationContext简单的配置一个或多个这些特殊的bean。如果你没有做任何配置,Spring MVC会用一系列的默认的Bean,因此你不是非配置这些bean不可。首先,看一下DispatcherServlet依赖的这些特殊的bean的表。
Table 22.1. Specail bean types in the WebApplicationContext

Bean类型 说明
HandlerMapping 将进来的请求映射到处理器上,并且有一系列前置和后置的处理器(处理器拦截器),处理器的具体细节由HandlerMapping实现决定。最常见的实现支持被注解的控制器,但也存在其他实现。
HandlerAdapter 帮助DispatcherServlet调用请求映射的处理器,但不管吃力气是否真的被调用。比如,调用被注解的控制器需要解析多个注解。因此,HandlerAdapter的主要目的是让DispatcherServlet不在关注这些细节。
HandlerExceptionResolver 将异常映射到视图,同时也允许更复杂的异常处理代码
ViewResolver 解析基于字符串的试图名字到真正的View类型
LocaleResolver & LocaleContextResolver 解析客户端正在使用的语言环境和时区,以便提供国际化的试图
ThemeResovler 解析你应用环境可以使用的主题,比如,提供个性化的布局
MultipartResolver 解析multi-part请求,比如,支持处理从HTML表单上传的文件
FlashMapManager 存储和检索“输入”和“输出”FlashMap,用来从一个请求传递属性到另一个请求,通常通过重定向

22.2.3 DispatcherServlet Processing Sequence

当你设置完DispatcherServlet,一个请求进到这个DispatcherServlet中,DispatcherServlet开始以下列顺序处理请求: WebApplicationContext被绑定为请求的属性,供控制器和其他元素搜索和使用。(绑定的默认的key为DispatcherServlet.WEb_APPLICATON_CONTEXT_ATTRIBUTE)。
语言环境解析器被绑定为请求的属性,使得在处理请求时(渲染视图,准备数据,等等),能够解析语言环境并使用。
* 如果你指定了一个multipart文件解析器,将检查请求是否有multiparts;如果发现了multiparts,请求将会被包装秤MultipartHttpServletReqeust,在过程中由其他元素更胜、深层的处理。见[22.10节,"Springs multipart (file upload) support"](https://docs.spring.io/spring/docs/4.3.13.RELEASE/spring-framework-reference/htmlsingle/#mvc-multipart)了解更多关于multipart处理。 * 搜索合适的处理器。如果发现了这个处理器,执行和这个处理器相关联的执行链(包含了前置处理器,后置处理器和控制器)会为准备模型或渲染被执行。 * 如果返回了一个模型,那么视图会被渲染。如果没有返回模型,(可能是前置处理器或后置处理器处于安全原因拦截了请求,)将不会有视图被渲染,因为请求已经完成了。 SpringDispatcherServlet也支持返回最后修改日期,由Servlet API特指的。为特定的请求检测最后修改日期的过程非常直接:DispatcherServlet查看合适的处理器映射,并测试这个处理器是否实现了LastModified接口。如果是,那么LastModified接口的long getLastModified(reqesut)方法的值会被返回到客户端。 你可以通过在声明Servlet时,往web.xml文件中添加Servlet初始化参数(init-param元素)来自定义你的DispatcherServlet`实例。下表列出了所支持的参数。

Table 22.2. DispathcerServlet initialization parameters

参数 说明
contextClass 实现了WebApplicationContext的类,它为Servlet初始化了上下文环境。默认使用XmlWebApplicationContext
contextConfigLocation 传给(由contextClass指定的)上下文实例的字符串,用来指定context的位置。字符串由多个字符串组成(用逗号分隔)来支持多个上下文。如果多个上下文中有bean被定义了两次,那么后定义的bean优先级更高
namespace WebApplicationContext的命名空间,默认是[servlet-name]-servlet